package cn.iocoder.yudao.module.system.service.partnercoupon;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
import cn.iocoder.yudao.module.promotion.api.coupon.CouponTemplateApi;
import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponTemplateRespDTO;
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum;
import cn.iocoder.yudao.module.system.controller.admin.partnercoupon.vo.PartnerCouponPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.partnercoupon.vo.PartnerCouponSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.partnercoupon.PartnerCouponDO;
import cn.iocoder.yudao.module.system.dal.dataobject.partnercouponshare.PartnerCouponShareDO;
import cn.iocoder.yudao.module.system.dal.mysql.partnercoupon.PartnerCouponMapper;
import cn.iocoder.yudao.module.system.dal.mysql.partnercouponshare.PartnerCouponShareMapper;
import cn.iocoder.yudao.module.system.enums.partner.PartnerCouponShareStatusEnum;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_TEMPLATE_EXPIRED;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;

/**
 * 合伙人优惠券 Service 实现类
 *
 * @author 万民匠心
 */
@Service
@Validated
public class PartnerCouponServiceImpl implements PartnerCouponService {

    @Resource
    private PartnerCouponMapper partnerCouponMapper;
    @Resource
    private PartnerCouponShareMapper partnerCouponShareMapper;
    @Resource
    private CouponTemplateApi couponTemplateApi;
    @Resource
    private CouponApi couponApi;

    @Override
    public Long createPartnerCoupon(PartnerCouponSaveReqVO createReqVO) {
        // 插入
        PartnerCouponDO partnerCoupon = BeanUtils.toBean(createReqVO, PartnerCouponDO.class);
        partnerCouponMapper.insert(partnerCoupon);
        // 返回
        return partnerCoupon.getId();
    }

    @Override
    public void updatePartnerCoupon(PartnerCouponSaveReqVO updateReqVO) {
        // 校验存在
        validatePartnerCouponExists(updateReqVO.getId());
        // 更新
        PartnerCouponDO updateObj = BeanUtils.toBean(updateReqVO, PartnerCouponDO.class);
        partnerCouponMapper.updateById(updateObj);
    }

    @Override
    public void deletePartnerCoupon(Long id) {
        // 校验存在
        validatePartnerCouponExists(id);
        // 删除
        partnerCouponMapper.deleteById(id);
    }

    private void validatePartnerCouponExists(Long id) {
        if (partnerCouponMapper.selectById(id) == null) {
            throw exception(PARTNER_COUPON_NOT_EXISTS);
        }
    }

    @Override
    public PartnerCouponDO getPartnerCoupon(Long id) {
        return partnerCouponMapper.selectById(id);
    }

    @Override
    public PageResult<PartnerCouponDO> getPartnerCouponPage(PartnerCouponPageReqVO pageReqVO) {
        return partnerCouponMapper.selectPage(pageReqVO);
    }

    @Override
    public void takPartnerCoupon(Long partnerCouponId, Long userId) {
        // 校验存在
        PartnerCouponDO partnerCouponDO = partnerCouponMapper.selectById(partnerCouponId);
        if (Objects.isNull(partnerCouponDO)) {
            throw exception(PARTNER_COUPON_NOT_EXISTS);
        }
        if (LocalDateTimeUtils.beforeNow(partnerCouponDO.getEndTime())) {
            throw exception(COUPON_TEMPLATE_EXPIRED);
        }

        Integer hasTakeCount = partnerCouponShareMapper.selectHasSendCount(partnerCouponId, userId);
        // 校验剩余数量
        if (partnerCouponDO.getTakeCount() + 1 > partnerCouponDO.getTotalCount()) {
            throw exception(PARTNER_COUPON_NOT_ENOUGH);
        }

        if (hasTakeCount >= partnerCouponDO.getLimitCount()) {
            throw exception(PARTNER_COUPON_LIMIT_COUNT);
        }
        List<CouponTemplateRespDTO> couponTemplateList = couponTemplateApi.getCouponTemplateList(Arrays.asList(partnerCouponDO.getTemplateId()));
        CouponTemplateRespDTO couponTemplateDTO = couponTemplateList.get(0);
        // 校验"固定日期"的有效期类型是否过期
        if (CouponTemplateValidityTypeEnum.DATE.getType().equals(couponTemplateDTO.getValidityType())) {
            if (LocalDateTimeUtils.beforeNow(couponTemplateDTO.getValidEndTime())) {
                throw exception(COUPON_TEMPLATE_EXPIRED);
            }
        }

        List<PartnerCouponShareDO> shareDOList = Lists.newArrayList();

        PartnerCouponShareDO couponShareDO  = BeanUtils.toBean(partnerCouponDO, PartnerCouponShareDO.class);
        couponShareDO.setPartnerCouponId(partnerCouponDO.getId());
        couponShareDO.setCreateTime(LocalDateTime.now());
        couponShareDO.setCreator(userId.toString());
        couponShareDO.setUpdateTime(LocalDateTime.now());
        couponShareDO.setUpdater(userId.toString());
        couponShareDO.setStatus(PartnerCouponShareStatusEnum.UNUSED.getStatus());
        couponShareDO.setId(null);
        shareDOList.add(couponShareDO);

        partnerCouponShareMapper.insertBatch(shareDOList);

        couponApi.takeCoupon(partnerCouponDO.getTemplateId(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.PARTNER,
                Boolean.TRUE, partnerCouponDO.getStartTime(), partnerCouponDO.getEndTime());
        // 3. 增加合伙人优惠劵模板的领取数量
        partnerCouponMapper.updateTakeCount(partnerCouponId, 1);
    }

    @Override
    public Boolean checkCanTake(Long partnerCouponId, Long userId) {
        PartnerCouponDO partnerCoupon = partnerCouponMapper.selectById(partnerCouponId);
        Boolean canTake = partnerCoupon.getTakeCount() < partnerCoupon.getTotalCount();
        if (canTake) {
            Integer hasTakeCount = partnerCouponShareMapper.selectHasSendCount(partnerCouponId, userId);
            if (hasTakeCount >= partnerCoupon.getLimitCount()) {
                canTake = Boolean.FALSE;
            }
        }
        return canTake;
    }

}